# -*- coding: utf-8 -*-
import time
import xlrd
import aiosmtplib
from asyncio import new_event_loop
from asyncio import set_event_loop
from asyncio import ensure_future
from asyncio import wait
from email.mime.text import MIMEText
from email.header import Header
from email.utils import parseaddr, formataddr
from SuperEmailSender.base_class import BaseClass


class SendEmail(BaseClass):
    name = 'send_email'

    def __init__(self, *args, **kwargs):
        super(SendEmail, self).__init__(*args, **kwargs)
        self.coding_type = 'utf-8'
        self.err_msg = {
            220: '‌服务就绪', 250: '请求动作正确完成', 235: '认证通过', 354: '开始发送邮件内容‌', 500: '语法错误，命令不能识别',
            501: '参数格式错误', 502: '命令不可实现', 503: '错误的命令序列', 504: '命令参数不可实现', 211: '系统状态或系统帮助响应‌',
            214: '帮助信息', 221: '服务关闭传输信道', 421: '服务未就绪，关闭传输信道‌', 251: '用户非本地，将转发向',
            450: '要求的邮件操作未完成，邮箱不可用（例如，邮箱忙）', 550: '要求的邮件操作未完成，邮箱未找到或不可访问',
            451: '放弃要求的操作；处理过程中出错', 552: '过量的存储分配，要求的操作未执行',
            553: '邮箱名不可用，要求的操作未执行（例如邮箱格式错误）', 554: '操作失败', 535: '用户验证失败', 334: '等待用户输入验证信息',
        }

    def my_format_addr(self, s):  # 格式化地址 也方便发送中文
        name, addr = parseaddr(s)
        return formataddr((Header(name, self.coding_type).encode(), addr))

    def get_msg(self, from_account, to_account, subject, content, content_type='plain'):
        msg = MIMEText(content, content_type, self.coding_type)
        msg['Subject'] = Header(subject, self.coding_type).encode()  # subject
        msg['From'] = self.my_format_addr(from_account)
        msg['To'] = self.my_format_addr(to_account)
        return msg

    def content_width(self, data):
        """
        表格横至
        :param data:
        :return:
        """
        td_1_list, td_2_list = [], []
        for key, value in data:
            td_1 = f"""
                <td valign="top" width="78" class="" style="border: 1px solid rgb(102, 102, 102); padding: 3px 8px;">
                    <div style="margin: 0px; padding: 0px; border: 0px; outline: 0px; clear: both;">
                        {key}
                    </div>
                </td>
                   """
            td_2 = f"""
                <td valign="top" width="78" class="" style="border: 1px solid rgb(102, 102, 102); padding: 3px 8px; color: {value[0]};">
                    <div style="margin: 0px; padding: 0px; border: 0px; outline: 0px; clear: both;">
                        {value[1]}
                    </div>
                </td>
                   """
            td_1_list.append(td_1)
            td_2_list.append(td_2)
        td_1_dumps = '\n'.join(td_1_list)
        td_2_dumps = '\n'.join(td_2_list)

        content = f"""
        <table id="aym_table_1582875106568" style="color: rgb(0, 0, 0); font-family: Tahoma, Arial, STHeiti, SimSun; font-size: 14px; border-collapse: collapse; border: 1px solid rgb(102, 102, 102);">
            <tbody>
            <tr>
                {td_1_dumps}
            </tr>
            <tr>
                {td_2_dumps}
            </tr>
            </tbody>
        </table>
               """
        return content

    def content_height(self, data):
        """
        表格纵至
        :return:
        """
        tr_list = []
        for key, value in data:
            tr = f"""
            <tr>
                <td style="border:1.0px solid #e0e0e0;text-align:center;width:140px;">{key}</td>
                <td style="border:1.0px solid #e0e0e0;color:{value[0]};padding:0 10.0px;text-align:center;width:140px;" class=" __aliyun_node_has_color">{value[1]}</td>
            </tr>
            """
            tr_list.append(tr)
        data = '\n'.join(tr_list)
        content = f"""
        <table style="border-collapse:collapse;border:1.0px solid #e0e0e0;line-height:46.0px;font-size:16.0px;">
            <tbody>
            {data}
            </tbody>
        </table>
                """
        return content

    def toHex(self, r=0, g=0, b=0):
        color = "#"
        color += str(hex(r)).replace('x', '0')[-2:]
        color += str(hex(g)).replace('x', '0')[-2:]
        color += str(hex(b)).replace('x', '0')[-2:]
        return color

    def color(self, data, cell_xf_index):
        colour_index = data.font_list[data.xf_list[cell_xf_index].font_index].colour_index
        colour_tuple = data.colour_map.get(colour_index)
        color = self.toHex(*colour_tuple if colour_tuple else (121, 121, 121))
        return color

    def create_send_email_data(self, data, table, i):
        rowVales = table.row_values(i)
        title_list = list(map(lambda x: str(x).strip(), table.row_values(1)))
        try:
            colour_list = list(
                map(lambda j: self.color(data=data, cell_xf_index=table.cell_xf_index(i, j)), range(len(rowVales))))
        except xlrd.biffh.XLRDError as e:
            colour_list = list(map(lambda j: self.toHex(r=121, g=121, b=121), range(len(rowVales))))
        return list(zip(title_list, zip(colour_list, rowVales)))

    def create_employee_data(self, host, port, account, passwd, format_var, path, **kwargs):
        self.logger.info(f'任务开始执行')
        start_time = time.time()
        loop = new_event_loop()
        set_event_loop(loop)
        task = ensure_future(self.main(host, port, account, passwd, format_var, path, **kwargs))
        loop.run_until_complete(task)
        loop.close()
        self.logger.info(f'任务执行完毕，总耗时：{time.time() - start_time}')

    async def main(self, host, port, account, passwd, format_var, path, **kwargs):
        start_time = time.time()
        try:
            data = xlrd.open_workbook(path, formatting_info=True)
        except NotImplementedError as e:
            data = xlrd.open_workbook(path)
        self.logger.info(f'文件读取完毕，耗时：{time.time() - start_time}')
        table = data.sheet_by_index(0)
        subject = ''.join(table.row_values(0)).strip()
        datas = [self.create_send_email_data(data, table, i) for i in range(2, table.nrows) if table.row_values(i)[1]]
        tasks = [ensure_future(self.execute_task(host, port, account, passwd, format_var, subject, d, **kwargs)) for d in datas]
        self.logger.info(f'创建邮件发送任务')
        if tasks: dones, pendings = await wait(tasks)

    async def execute_task(self, host, port, account, passwd, format_var, subject, data, **kwargs):
        """
        一个账户发送一条邮件
        """
        start_time = time.time()
        email = data.pop(1)
        retry = kwargs.pop('retry', 3)
        content = self.content_height(data=data) if format_var else self.content_width(data=data)
        kwarg = {'EMAIL_HOST': host, 'FROM_ACCOUNT': account, 'FROM_PASSWD': passwd, 'EMAIL_PORT': port,
                 'to_account': email[1][1], 'subject': subject, 'content': content, 'content_type': 'html'}
        kwarg.update(kwargs)
        for i in range(int(retry)+1):
            result = await self.async_send_email(**kwarg)
            if not result[0]:
                msg = f'{data[0][1][1]} {email[1][1]} {subject} 邮件发送成功！{result[-1]} 耗时：{time.time() - start_time}'
                self.logger.info(msg)
                break
            else:
                msg = f'{data[0][1][1]} {email[1][1]} {subject} 邮件发送失败！{self.err_msg.get(result[0], result[-1])} 耗时：{time.time() - start_time}'
                self.logger.error(msg)

    async def async_send_email(self, EMAIL_HOST, EMAIL_PORT, FROM_ACCOUNT, FROM_PASSWD, to_account, subject, content, content_type='plain', **kwargs):
        msg = self.get_msg(FROM_ACCOUNT, to_account, subject, content, content_type)
        try:
            async with aiosmtplib.SMTP(hostname=EMAIL_HOST, port=EMAIL_PORT, **kwargs) as smtp:
                result = await smtp.login(FROM_ACCOUNT, FROM_PASSWD)
                result = await smtp.send_message(msg)
                await smtp.quit()
        except aiosmtplib.SMTPException as e:
            self.logger.debug(f'{to_account} {subject} ' + repr(e))
            result = e.args if hasattr(e, 'args') else (repr(e),)
        return result

